using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ALib;
using ALib.Data.CSVOperation;
using ALib.Data.IO;
using ALib.Misc;
using Remoting;
using TradingLab.Data;

namespace TradingPlatform
{
    public class StrategyClient
    {
        protected static AlphaRemotingObject _remoteObject;

        public bool Connected
        {
            get
            {
                bool result = _remoteObject != null;
                return result;
            }
        }

        public void Connect()
        {
            try
            {
                Configuration configuration = new Configuration(@"Configuration\ConnectionToStrategy.txt");
                string ip = configuration.GetString(KeyWordStrategyConnection.StrategyServerIp);
                string port = configuration.GetString(KeyWordStrategyConnection.StrategyServerPort);
                if (_remoteObject == null)
                {
                    string url = string.Format(@"tcp://{0}:{1}/Alpha", ip, port);
                    _remoteObject = new AlphaRemotingObject(url);
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public string Init()
        {
            string result = string.Empty;
            if (Connected)
            {
                result = _remoteObject.Request("Init");
            }
            return result;
        }

        public string Status()
        {
            string result = string.Empty;
            if (Connected)
            {
                result = _remoteObject.Request("Status");
            }
            return result;
        }

        public string SaveLog()
        {
            string result = string.Empty;
            if (Connected)
            {
                result = _remoteObject.Request("SaveLog");
            }
            return result;
        }

        public void Disconnect()
        {
            if (Connected)
            {
                SaveLog();
                _remoteObject = null;
            }
        }

        public SortedList<string, List<string>> Calc(DateTime tradingPlatformTime, SortedList<string, double[]> bars, OrderManagementDb orderManagementDb, SortedList<string, string> strategyTickerNameList, TickerInfoDb tickerInfoDb)
        {
            SortedList<string, List<string>> result = new SortedList<string, List<string>>();

            if (Connected)
            {
                TimeData timeData = new TimeData();

                foreach (KeyValuePair<string, double[]> tickerName_bar in bars)
                {
                    string tickerName = tickerName_bar.Key;
                    string strategyTickerName = strategyTickerNameList[tickerName];
                    double[] bar = tickerName_bar.Value;
                    double openPosition = orderManagementDb == null || !orderManagementDb.OpenPositionList.ContainsKey(tickerName) ? 0 : orderManagementDb.OpenPositionList[tickerName];
                    int tradingPlatformTimeZoneIndex = int.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.tradingPlatformTimeZoneIndex));
                    int exchangeTimeZoneIndex = int.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.exchangeTimeZoneIndex));
                    string tradingSessionString = tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.tradingHours);
                    double exchangeRate = tickerInfoDb.GetExchangeRateXxxUsd(tickerName);

                    // 20100416 093300,Futures_CSI300_201005

                    timeData.Add(strategyTickerName
                                 , bar[0] // Open
                                 , bar[1] // High
                                 , bar[2] // Low
                                 , bar[3] // Close
                                 , bar[4] // Volume
                                 , openPosition // existingOpenPosition
                                 , tradingPlatformTimeZoneIndex // tradingPlatformTimeZoneIndex
                                 , exchangeTimeZoneIndex // exchangeTimeZoneIndex
                                 , tradingSessionString
                                 , exchangeRate // Exchange rate
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategyPointValue))// Point value
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategyMinMove))// Min move
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategyLotSize))// Lot size
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategyCommissionOnRate))// CommissionOnRate
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategyCommissinPerShareInXxx))// Commission per share in XXX 
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategyMinCommissionInXxx))// Min commission in XXX
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategyMaxCommissionInXxx))// Max commission in XXX
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategyStampDutyRate))// Stamp duty and slippage rate
                                 , double.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.strategySlippagePoints))// Slippage per share in XXX
                        );

                }

                string calcCommand = timeData.ToCalcCommandEx(tradingPlatformTime);
                string strategyStatusAndNewOrderString = _remoteObject.Request(calcCommand);
                //Logger.WriteLine(@"StratetyServerReplyLog.txt", tradingPlatformTime.ToString(DateTimeFormatType.Simple) + "," +  strategyStatusAndNewOrderString);


                string[] records = strategyStatusAndNewOrderString.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);

                foreach (string record in records)
                {
                    string respondType = record.Split(new char[] {','})[0];

                    switch (respondType)
                    {
                        case KeyWordsStrategy.StrategyStatus:
                            if (!result.ContainsKey(KeyWordsStrategy.StrategyStatus))
                            {
                                result.Add(KeyWordsStrategy.StrategyStatus, new List<string>());   
                            }
                            result[KeyWordsStrategy.StrategyStatus].Add(record);
                            break;
                        case KeyWordsStrategy.SendOrder:
                            if (!result.ContainsKey(KeyWordsStrategy.SendOrder))
                            {
                                result.Add(KeyWordsStrategy.SendOrder,new List<string>());
                            }
                            result[KeyWordsStrategy.SendOrder].Add(record);
                            break;
                        case KeyWordsStrategy.CancelOrder:
                            if (!record.StartsWith(KeyWordsStrategy.CancelOrder))
                            {
                                result[KeyWordsStrategy.CancelOrder].Add(record);
                            }
                            result[KeyWordsStrategy.CancelOrder].Add(record);
                            break;
                        default:
                            throw new Exception("No such repond type.");
                    }
                }
            }

            return result;
        }

        public void PreloadData(TickerInfoDb tickerInfoDb, SortedList<string,string> strategyTickerNameList, string dataPath, int preloadDays)
        {
            GoodValue.Assert(preloadDays > 0);

            if (Connected)
            {
                List<string> tickerNames = tickerInfoDb.TickerNameList;
                SortedList<long, SortedList<string, BarFormer>> dataSeries = new SortedList<long, SortedList<string, BarFormer>>();

                // Format the data series.
                foreach (string tickerName in tickerNames)
                {
                    for (DateTime time = DateTime.Now.Date.AddDays(-preloadDays); time < DateTime.Now.AddMinutes(-1); time=time.AddMinutes(1))
                    {
                        long tradingPlatformMinuteIndex = long.Parse(time.ToString("yyyyMMddHHmm00"));
                        if (!dataSeries.ContainsKey(tradingPlatformMinuteIndex))
                        {
                            dataSeries.Add(tradingPlatformMinuteIndex, new SortedList<string, BarFormer>());
                        }
                        if (!dataSeries[tradingPlatformMinuteIndex].ContainsKey(tickerName))
                        {
                            dataSeries[tradingPlatformMinuteIndex].Add(tickerName, new BarFormer());
                        }
                    }
                }

                // Load data file files
                foreach (string tickerName in tickerNames)
                {
                    DirectoryInfo tickerDataDir = new DirectoryInfo(string.Format(@"{0}\{1}", dataPath, tickerName));
                    if (tickerDataDir.Exists)
                    {
                        List<FileInfo> minuteFiles = Dir.GetAllFiles(tickerDataDir, "*.csv");

                        int tradingPlatformTimeZoneIndex = int.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.tradingPlatformTimeZoneIndex));
                        int exchangeTimeZoneIndex = int.Parse(tickerInfoDb.GetTickerInfoItem(tickerName, TickerInfoItemType.exchangeTimeZoneIndex));
                        UtcConverter utcConverter = new UtcConverter(tradingPlatformTimeZoneIndex, exchangeTimeZoneIndex);

                        foreach (FileInfo minuteFile in minuteFiles)
                        {
                            long exchangeMinuteIndex = long.Parse(minuteFile.Directory.Name + minuteFile.Name.Replace(".csv", "").Substring(0, 4) + "00");
                            DateTime exchangeTime = MinuteIndexToDateTime(exchangeMinuteIndex);
                            DateTime tradingPlatformTime = utcConverter.ExchangeTimeToTradingPlatformTime(exchangeTime);
                            long tradingPlatformMinuteIndex = long.Parse(tradingPlatformTime.ToString(DateTimeFormatType.Simple).Replace(" ", ""));

                            if (dataSeries.ContainsKey(tradingPlatformMinuteIndex))
                            {
                                BarFormer barFormer = dataSeries[tradingPlatformMinuteIndex][tickerName];

                                List<string[]> ticks = CSVEditor.Open(minuteFile.FullName);
                                foreach (string[] tick in ticks)
                                {
                                    //double price = double.Parse(tick[6]);
                                    double bid = double.Parse(tick[3]);
                                    double ask = double.Parse(tick[4]);
                                    double last = double.Parse(tick[6]);
                                    double volume = double.Parse(tick[7]);

                                    if (IsGoodPrice(bid) && IsGoodPrice(ask) && IsGoodPrice(last) && !double.IsNaN(volume) && volume >= 0)
                                    {
                                        if (true)
                                        {
                                            if (last < bid - bid * 0.01)
                                            {
                                                last = bid;
                                            }
                                            if (ask + 0.01 * ask < last)
                                            {
                                                last = ask;
                                            }

                                            //double last = (bid + ask) / 2;
                                            barFormer.UpdateWithTickPrice(last);
                                            barFormer.UpdateWithTickVolume(volume);
                                        }
                                    }
                                }
                            }
                        }   
                    }
                }

                int countKey = 0;

                foreach (KeyValuePair<long, SortedList<string, BarFormer>> minuteIndex_Bar in dataSeries)
                {
                    long minuteIndex = minuteIndex_Bar.Key;
                    DateTime tradingPlatformTime = MinuteIndexToDateTime(minuteIndex);

                    SortedList<string, double[]> minuteBars = new SortedList<string, double[]>();
                    foreach (KeyValuePair<string, BarFormer> tickerName_Bar in minuteIndex_Bar.Value)
                    {
                        string tickerName = tickerName_Bar.Key;
                        BarFormer barFormer = tickerName_Bar.Value;
                        double[] bar = new double[]
                                           {
                                               barFormer.Open, barFormer.High, barFormer.Low, barFormer.Close,
                                               barFormer.Volume
                                           };
                        minuteBars.Add(tickerName, bar);   
                        //if (!double.IsNaN(bar[0]) && bar[0]>0
                        //    && !double.IsNaN(bar[1]) && bar[1] > 0
                        //    && !double.IsNaN(bar[2]) && bar[2] > 0
                        //    && !double.IsNaN(bar[3]) && bar[3] > 0
                        //    && !double.IsNaN(bar[4]) && bar[4] >= 0)
                        //{
                            
                        //}
                    }

                    SortedList<string, double> openPositinList = new SortedList<string, double>();
                    foreach (string tickerName in tickerNames)
                    {
                        openPositinList.Add(tickerName, 0);
                    }

                    if (tradingPlatformTime == new DateTime(2011,1,1))
                    {
                    }

                    Calc(tradingPlatformTime, minuteBars, null, strategyTickerNameList, tickerInfoDb);

                    if (++countKey % 500 == 0)
                    {
                        int q = 0;
                        q++;
                    }
                }
            }
        }

        private static bool IsGoodPrice(double price)
        {
            bool result = !double.IsInfinity(price) && !double.IsNaN(price) && price > 0;
            return result;
        }

        private static DateTime MinuteIndexToDateTime(long minuteIndex)
        {
            string dateString = minuteIndex.ToString().Substring(0, 8);
            string minuteString = minuteIndex.ToString().Substring(8, 6);
            DateTime time = DateTimeConverter.ToDateTime(dateString, minuteString);
            return time;
        }
    }
}
